﻿using System;
using System.Linq;
using TSU.FAMC.ComputerEngineering.Classes.Circuits.Events;
using TSU.FAMC.ComputerEngineering.Classes.Enums;

namespace TSU.FAMC.ComputerEngineering.Classes.Circuits.Basis
{
    /// <summary>
    /// NotOr gate element with two or more inputs and one output.
    /// </summary>
    public class NOrGate : Gate
    {
        // Methods

        /// <summary>
        /// Default construcotor.
        /// </summary>
        public NOrGate()
        {
            // contraining input and output interface
            Outputs.OnModified += Outputs_OnModified;
        }

        /// <summary>
        /// Processes inputs signals and produces a result signal.
        /// </summary>
        /// <returns>Resulting signal. If Value of the signal is BooleanValue.UNDEFINED it means processing failed.</returns>
        public override Signal Process()
        {
            if (InputSignals.Any(s => s.Value == BooleanValue.True))
            {
                return new Signal { Value = BooleanValue.False };
            }

            if (InputSignals.Count < 2)
            {
                return new Signal { Value = BooleanValue.Undefined };
            }

            // returning result signal
            var resultSignal = new Signal { Value = BooleanValue.False };
            return ~InputSignals.Aggregate(resultSignal, (current, inputSignal) => current | inputSignal);
        }


        // Event handlers

        /// <summary>
        /// OnModified event handler for input interface.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event arguments.</param>
        private void Outputs_OnModified(object sender, CircuitInterfaceEventArgs e)
        {
            if (Outputs.Count > 1)
            {
                throw new InvalidOperationException("NOrGate element has to have only one output. Use Joint element for n-m relation.");
            }
        }

        /// <summary>
        /// Clones not-or element.
        /// </summary>
        /// <returns>Cloned not-or element.</returns>
        public override object Clone()
        {
            return new NOrGate
            {
                Delay = Delay,
                Id = Id,
                Name = Name
            };
        }
    }
}
